package com.aizuda.easyManagerTool.service.docker.impl;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.aizuda.easy.security.domain.Rep;
import com.aizuda.easy.security.domain.Req;
import com.aizuda.easyManagerTool.domain.dto.PageDTO;
import com.aizuda.easyManagerTool.domain.dto.docker.DockerPullImagesDTO;
import com.aizuda.easyManagerTool.domain.dto.docker.DockerTagDelDTO;
import com.aizuda.easyManagerTool.domain.dto.terminal.SSHInfoDTO;
import com.aizuda.easyManagerTool.domain.entity.docker.DockerCloudEntity;
import com.aizuda.easyManagerTool.domain.entity.docker.DockerCloudUserEntity;
import com.aizuda.easyManagerTool.domain.entity.docker.DockerConfigEntity;
import com.aizuda.easyManagerTool.domain.entity.setting.SettingUserEntity;
import com.aizuda.easyManagerTool.domain.vo.PageVO;
import com.aizuda.easyManagerTool.domain.vo.docker.DockerCloudFindImageVO;
import com.aizuda.easyManagerTool.domain.vo.docker.DockerCloudFindVO;
import com.aizuda.easyManagerTool.domain.vo.docker.DockerCloudTagListVO;
import com.aizuda.easyManagerTool.domain.vo.docker.DockerConfigFindVO;
import com.aizuda.easyManagerTool.domain.vo.server.ServerCompleteVO;
import com.aizuda.easyManagerTool.domain.vo.setting.SettingUserVO;
import com.aizuda.easyManagerTool.domain.vo.socket.SocketMessageVO;
import com.aizuda.easyManagerTool.mapper.docker.DockerCloudMapper;
import com.aizuda.easyManagerTool.mapper.docker.DockerCloudUserMapper;
import com.aizuda.easyManagerTool.mapper.docker.DockerConfigMapper;
import com.aizuda.easyManagerTool.mapper.server.ServerMapper;
import com.aizuda.easyManagerTool.mapper.setting.SettingUserMapper;
import com.aizuda.easyManagerTool.sdk.docker.APIHttpTemplate;
import com.aizuda.easyManagerTool.sdk.docker.DockerAPI;
import com.aizuda.easyManagerTool.sdk.docker.DockerConfig;
import com.aizuda.easyManagerTool.sdk.docker.api.DockerRegistryAPI;
import com.aizuda.easyManagerTool.sdk.docker.vo.RegistryGetManifestsVO;
import com.aizuda.easyManagerTool.sdk.docker.vo.RegistryImagesTagListVO;
import com.aizuda.easyManagerTool.service.docker.DockerCloudService;
import com.aizuda.easyManagerTool.service.terminal.ScriptService;
import com.aizuda.easyManagerTool.util.AssertUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.http.client.methods.HttpGet;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.socket.TextMessage;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class DockerCloudServiceImpl extends ServiceImpl<DockerCloudMapper, DockerCloudEntity> implements DockerCloudService {

    @Resource
    private DockerCloudMapper dockerCloudMapper;
    @Resource
    private DockerConfigMapper dockerConfigMapper;
    @Resource
    private ServerMapper serverMapper;
    @Resource
    private SettingUserMapper settingUserMapper;
    @Resource
    private DockerCloudUserMapper dockerCloudUserMapper;
    @Resource
    private ScriptService scriptService;

    @Override
    public Rep<PageVO<DockerCloudFindVO>> find(Req<PageDTO<DockerCloudEntity>, SettingUserVO> req) {
        PageDTO<DockerCloudEntity> pageDTO = req.getData();
        DockerCloudEntity data = pageDTO.getData();
        AssertUtil.objIsNull(data.getDockerId(), "请选择服务器配置");
        Page<DockerCloudEntity> page = new Page<DockerCloudEntity>(pageDTO.getCurrent(), pageDTO.getSize());
        data.setUserId(req.getUser().getId());
        // 查询 唯一条件是要根据 权限查询
        IPage<DockerCloudFindVO> cloudFindVOIPage = dockerCloudMapper.find(page, ObjectUtil.isEmpty(data)? new DockerCloudEntity():data);
        // 统计每个项目的 tage 数量
        DockerConfigEntity dockerConfigEntity = dockerConfigMapper.selectById(data.getDockerId());
        DockerAPI dockerAPI = new DockerConfig.Builder()
                .registryUrl(dockerConfigEntity.getConfigUrl())
                .userName(dockerConfigEntity.getConfigUserName())
                .password(dockerConfigEntity.getConfigPassword())
                .build();
        DockerRegistryAPI dockerRegistryAPI = dockerAPI.getDockerRegistryAPI();

        List<String> repositories = dockerRegistryAPI.getImages().getRepositories();

        DockerCloudFindImageVO dockerCloudFindImageVO = new DockerCloudFindImageVO();
        List<DockerCloudFindVO> records = cloudFindVOIPage.getRecords();
        records.parallelStream().forEach(item -> {
            List<DockerCloudFindImageVO> collect = repositories.parallelStream().filter(i -> item.getDockerProject().equals(i.split("/")[0]))
                    .map(ik -> {
                        RegistryImagesTagListVO imagesTagList = dockerRegistryAPI.getImagesTagList(ik);
                        DockerCloudFindImageVO dockerCloudFindImageVO1 = BeanUtil.copyProperties(dockerCloudFindImageVO, DockerCloudFindImageVO.class);
                        dockerCloudFindImageVO1.setCloudId(item.getId());
                        dockerCloudFindImageVO1.setConfigId(item.getDockerId());
                        if(ObjectUtil.isEmpty(imagesTagList)){
                            return dockerCloudFindImageVO1;
                        }
                        dockerCloudFindImageVO1.setImage(imagesTagList.getName());
                        dockerCloudFindImageVO1.setTagCount(CollUtil.isEmpty(imagesTagList.getTags())? 0: imagesTagList.getTags().size());
                        return dockerCloudFindImageVO1;
                    }).filter(ik -> ik.getTagCount() > 0)
                    .collect(Collectors.toList());
            item.setImageCount(collect.size());
            item.setImages(collect);
        });

        PageVO<DockerCloudFindVO> pageVO = new PageVO<DockerCloudFindVO>(pageDTO)
                .setTotal(cloudFindVOIPage.getTotal())
                .setRecords(records);

        return Rep.ok(pageVO);
    }

    @Override
    public Rep<List<DockerConfigFindVO>> findConfig(Req<DockerConfigEntity, SettingUserVO> req) {
        DockerConfigEntity data = req.getData();
        List<DockerConfigFindVO> dockerConfigFindVOS = dockerConfigMapper.find(data);
        if(CollUtil.isEmpty(dockerConfigFindVOS)){
            dockerConfigFindVOS = new ArrayList<>();
        }
        return Rep.ok(dockerConfigFindVOS);
    }

    @Transactional
    @Override
    public Rep<DockerCloudEntity> edit(Req<DockerCloudEntity, SettingUserVO> req) {
        // 默认
        DockerCloudEntity data = req.getData();
        SettingUserVO user = req.getUser();
        AssertUtil.objIsNull(data.getDockerProject(),"项目名称不能为空");
        AssertUtil.objIsNull(data.getDockerAccessLevel(),"请选择项目访问级别");
        AssertUtil.objIsNull(data.getDockerId(),"请选择配置服务器");
        if(ObjectUtil.isNotEmpty(data.getId()) && !user.getId().equals(user.getTenantId())){
            DockerCloudEntity dockerCloudEntity = dockerCloudMapper.findIdAndUserId(data.getId(),user.getId());
            AssertUtil.objIsNull(dockerCloudEntity,"没有权限编辑");
        }
        // 访问级别是公开，所用用户均可访问
        if(!data.getDockerAccessLevel()) {
            List<SettingUserEntity> all = settingUserMapper.findAll(user.getTenantId());
            List<String> collect = all.stream().map(SettingUserEntity::getId).map(String::valueOf).collect(Collectors.toList());
            if(CollUtil.isNotEmpty(all)) {
                data.setUserIds(String.join(",",collect));
            }
        }else{
            AssertUtil.objIsNull(data.getUserIds(),"请选择可访问用户");
        }

        Set<Integer> split = Arrays.stream(data.getUserIds().split(",")).map(Integer::valueOf).collect(Collectors.toSet());
        // 删除管理员
        split.remove(user.getTenantId());
        // 添加自己
        if(!user.getId().equals(user.getTenantId())){
            data.setUserId(user.getId());
            split.add(user.getId());
        }
        data.setUserIds(String.join(",", split.stream().map(String::valueOf).toArray(String[]::new)));
        // 保存
        DockerConfigEntity dockerConfigEntity = dockerConfigMapper.selectById(data.getDockerId());
        data.setServerId(dockerConfigEntity.getServerId());
        saveOrUpdate(data);
        // 先删后增
        dockerCloudUserMapper.clearCloudId(data.getId());
        List<DockerCloudUserEntity> collect = split.stream().map(i -> {
            DockerCloudUserEntity dockerCloudUserEntity = new DockerCloudUserEntity();
            dockerCloudUserEntity.setUserId(i);
            dockerCloudUserEntity.setCloudId(data.getId());
            dockerCloudUserEntity.setTenantId(user.getTenantId());
            dockerCloudUserEntity.setCreateTime(new Date());
            dockerCloudUserEntity.setUpdateTime(new Date());
            return dockerCloudUserEntity;
        }).collect(Collectors.toList());
        DockerCloudUserEntity dockerCloudUserEntity = new DockerCloudUserEntity();
        dockerCloudUserEntity.setUserId(user.getTenantId());
        dockerCloudUserEntity.setCloudId(data.getId());
        dockerCloudUserEntity.setTenantId(user.getTenantId());
        dockerCloudUserEntity.setCreateTime(new Date());
        dockerCloudUserEntity.setUpdateTime(new Date());
        collect.add(dockerCloudUserEntity);
        // 保存user
        dockerCloudUserMapper.insertBatch(collect);
        return Rep.ok(data);
    }

    @Transactional
    @Override
    public Rep<DockerCloudEntity> del(Req<DockerCloudEntity, SettingUserVO> req) {
        DockerCloudEntity data = req.getData();
        SettingUserVO user = req.getUser();
        AssertUtil.objIsNull(data.getId(),"数据错误");
        if(user.getId().equals(user.getTenantId())){
            dockerCloudMapper.deleteById(data.getId());
        }else {
            int num = dockerCloudMapper.deleteByIdAndUserId(data.getId(), user.getId());
            if (num == 0) {
                return Rep.error(500, "没有权限删除");
            }
        }
        dockerCloudUserMapper.clearCloudId(data.getId());
        // 考虑是否也删除所包含的镜像和所有tag
        return Rep.ok();
    }

    @Override
    public Rep<DockerConfigEntity> editConfig(Req<DockerConfigEntity, SettingUserVO> req) {
        DockerConfigEntity data = req.getData();
        AssertUtil.objIsNull(data.getServerId(),"请选择服务器");
        AssertUtil.objIsNull(data.getConfigUrl(),"请填Docker Registry地址");
        // 执行初始化
        ServerCompleteVO byId = serverMapper.findById(data.getServerId());
        SSHInfoDTO sshInfoDTO = new SSHInfoDTO();
        BeanUtil.copyProperties(byId,sshInfoDTO);
        HttpGet httpGet = new HttpGet(data.getConfigUrl());
        APIHttpTemplate apiHttpTemplate = new APIHttpTemplate();
        try {
            String auth = Base64.getEncoder().encodeToString((data.getConfigUserName() + ":" + data.getConfigPassword()).getBytes());
            httpGet.setHeader("Authorization", "Basic " + auth);
            String get = apiHttpTemplate.BASE(httpGet);
            AssertUtil.objEQ(get,"{}","连接失败，检查地址是否配置正确");
        }catch (Exception e){
            return Rep.error(500,e.getMessage());
        }
        DockerConfigEntity dockerConfigEntity = dockerConfigMapper.findByServerId(data.getServerId());
        if(ObjectUtil.isEmpty(dockerConfigEntity)){
            dockerConfigMapper.insert(data);
        }else {
            dockerConfigEntity.setConfigUrl(data.getConfigUrl());
            dockerConfigMapper.updateById(dockerConfigEntity);
        }
        return Rep.ok(data);
    }

    @Override
    public Rep<List<DockerCloudTagListVO>> tagList(Req<DockerCloudEntity, SettingUserVO> req) {
        // 查询这个库的信息
        DockerCloudEntity data = req.getData();
        AssertUtil.objIsNull(data.getDockerProject(), "数据错误");
        DockerConfigEntity dockerConfigEntity = dockerConfigMapper.selectById(data.getDockerId());
        DockerAPI dockerAPI = new DockerConfig.Builder()
                .registryUrl(dockerConfigEntity.getConfigUrl())
                .userName(dockerConfigEntity.getConfigUserName())
                .password(dockerConfigEntity.getConfigPassword())
                .build();
        DockerRegistryAPI dockerRegistryAPI = dockerAPI.getDockerRegistryAPI();
        return Rep.ok(toDockerCloudTagListVO(dockerRegistryAPI,data.getDockerProject(), data.getId(), data.getDockerId()));
    }

    @Override
    public Rep<List<DockerCloudTagListVO>> tagDel(Req<DockerTagDelDTO, SettingUserVO> req) {
        DockerTagDelDTO data = req.getData();
        AssertUtil.objIsNull(data.getDockerId(), "数据错误");
        AssertUtil.objIsNull(data.getImage(), "数据错误");
        AssertUtil.objIsNull(data.getTag(), "数据错误");
        DockerConfigEntity dockerConfigEntity = dockerConfigMapper.selectById(data.getDockerId());
        DockerAPI dockerAPI = new DockerConfig.Builder()
                .registryUrl(dockerConfigEntity.getConfigUrl())
                .userName(dockerConfigEntity.getConfigUserName())
                .password(dockerConfigEntity.getConfigPassword())
                .build();
        DockerRegistryAPI dockerRegistryAPI = dockerAPI.getDockerRegistryAPI();
        dockerRegistryAPI.delManifests(data.getImage(), data.getTag());
        return Rep.ok(toDockerCloudTagListVO(dockerRegistryAPI,data.getImage(), data.getConfigId(), data.getDockerId()));
    }

    @Override
    public Rep<List<DockerCloudEntity>> pullImages(Req<DockerPullImagesDTO, SettingUserVO> req) {
        DockerPullImagesDTO data = req.getData();
        SettingUserVO user = req.getUser();
        List<ServerCompleteVO> serverCompleteVOS = serverMapper.findByIds(data.getServerIds());
        DockerConfigEntity dockerConfigEntity = dockerConfigMapper.selectById(data.getConfigId());
        SSHInfoDTO sshInfoDTO = new SSHInfoDTO();
        String configUrl = dockerConfigEntity.getConfigUrl();
        configUrl = configUrl.substring(configUrl.indexOf("//") + 2);
        final String url = configUrl.substring(0,configUrl.indexOf("/")+1);
        SocketMessageVO<String> socketMessage = new SocketMessageVO();
        Thread threa = new Thread(() -> {
            serverCompleteVOS.forEach(i -> {
                Thread thread = new Thread(() -> {
                    String script = url + data.getImage() + ":" + data.getTag();
                    if (StrUtil.isNotEmpty(data.getRunScript())) {
                        script += " \"" + data.getRunScript() + "\"";
                    } else {
                        script += " \"\"";
                    }
                    if (data.getDelPredecessor()) {
                        script += " " + true;
                    } else {
                        script += " " + false;
                    }
                    if (StrUtil.isNotBlank(data.getContainerName())) {
                        script += " " + data.getContainerName();
                    } else {
                        script += " \"\"";
                    }
                    SSHInfoDTO sshInfoDTO1 = BeanUtil.copyProperties(sshInfoDTO, SSHInfoDTO.class);
                    BeanUtil.copyProperties(i, sshInfoDTO1);
                    scriptService.execScript("dockerCloud" + i.getId()
                            , user, sshInfoDTO1, "sh/docker/dockerPullImage.sh"
                            , script, (s, webSocketSession) -> {
                                try {
                                    socketMessage.setType("dockerCloud-time" + data.getCloudId());
                                    socketMessage.setObj("200");
                                    webSocketSession.sendMessage(new TextMessage(JSONUtil.toJsonStr(socketMessage)));
                                } catch (Exception e) {
                                    log.warn("socket断链");
                                }
                            });
                });
                thread.setName("docker云仓镜像拉取-" + i.getId());
                thread.start();
            });
        });
        threa.setName("docker云仓镜像拉取-" + data.getImage() + ":" + data.getTag());
        threa.start();
        // 查询
        return Rep.ok();
    }


    private List<DockerCloudTagListVO> toDockerCloudTagListVO(DockerRegistryAPI dockerRegistryAPI,String image,Integer configId,Integer dockerId){
        RegistryImagesTagListVO imagesTagList = dockerRegistryAPI.getImagesTagList(image);
        if(ObjectUtil.isEmpty(imagesTagList.getTags())){
            return new ArrayList<>();
        }
        DockerCloudTagListVO dockerCloudTagListVO = new DockerCloudTagListVO();
        List<DockerCloudTagListVO> collect = imagesTagList.getTags().parallelStream().map(item -> {
            DockerCloudTagListVO dockerCloudTagListVO1 = BeanUtil.copyProperties(dockerCloudTagListVO, DockerCloudTagListVO.class);
            dockerCloudTagListVO1.setTag(item);
            dockerCloudTagListVO1.setImage(image);
            dockerCloudTagListVO1.setCloudId(configId);
            dockerCloudTagListVO1.setConfigId(dockerId);
            RegistryGetManifestsVO manifests = dockerRegistryAPI.getManifests(image, item);
            dockerCloudTagListVO1.setTagInfo(manifests);
            return dockerCloudTagListVO1;
        }).collect(Collectors.toList());
        return collect;
    }

}
